#include<netinet/in.h>   // sockaddr_in
#include<sys/types.h>    // socket
#include<sys/socket.h>   // socket
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/select.h>   // select
#include<sys/ioctl.h>
#include<sys/time.h>
#include<iostream>
#include<vector>
#include<map>
#include <string.h>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<cstring>

#include "tcpServer.h"
using namespace std;

void Sprintf_HexData( char * headData, unsigned char * data, int data_len )
{ 
	printf(headData); 
 	int i =0;
	for( i=0; i<data_len; i++ ) 
	{
		printf("%02x ", (data[i])); 
	}
	printf(" \n"); 
}



// thread function
void* heart_handler(void* arg)
{
    cout << "The heartbeat checking thread started.\n";
    Server* s = (Server*)arg;
    while(1)
    {
        map<int, pair<string, int> >::iterator it = s->mmap.begin();
        for( ; it!=s->mmap.end(); )
        {   
            if(it->second.second == 5)   // 6s*5没有收到心跳包，判定客户端掉线
            {
                cout << "The client " << it->second.first << " has be offline.\n";
 
                int fd = it->first;
                close(fd);            // 关闭该连接
                FD_CLR(fd, &s->master_set);
                if(fd == s->max_fd)      // 需要更新max_fd;
                {
                    while(FD_ISSET(s->max_fd, &s->master_set) == false)
                        s->max_fd--;
                }
 
                s->mmap.erase(it++);  // 从map中移除该记录
            }
            else if(it->second.second < 5 && it->second.second >= 0)
            {
                it->second.second += 1;
                ++it;
            }
            else
            {
                ++it;
            }
        }
        sleep(6);   // 定时6秒
    }
}

Server::Server(int port)
{
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(port);
    // create socket to listen
    listen_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(listen_fd < 0)
    {
        cout << "Create Socket Failed!";
        exit(1);
    }
    int opt = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}
 
Server::~Server()
{
    for(int fd=0; fd<=max_fd; ++fd)
    {
        if(FD_ISSET(fd, &master_set))
        {
            close(fd);
        }
    }
}
 
void Server::Bind()
{
    if(-1 == (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
    {
        cout << "Server Bind Failed!";
        exit(1);
    }
    cout << "Bind Successfully.\n"; 
}
 
void Server::Listen(int queue_len)
{
    if(-1 == listen(listen_fd, queue_len))
    {
        cout << "Server Listen Failed!";
        exit(1);
    }
    cout << "Listen Successfully.\n";
}
 
void Server::Accept()
{
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
 
    int new_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
    if(new_fd < 0)
    {
        cout << "Server Accept Failed!";
        exit(1);
    }
 
    string ip(inet_ntoa(client_addr.sin_addr));    // 获取客户端IP
 
    cout << ip << " new connection was accepted.\n";
 
    mmap.insert(make_pair(new_fd, make_pair(ip, 0)));
 
    // 将新建立的连接的fd加入master_set
    FD_SET(new_fd, &master_set);
    if(new_fd > max_fd)
    {
        max_fd = new_fd;
    }
}   
#include <pthread.h>
#include "rtdb_fun.h"

void Server::Recv(int nums)
{
	char strbuffer[15000];  //存放数据的缓冲区
	char head[10];
	
    for(int fd=0; fd<=max_fd; ++fd)
    {
		memset(strbuffer, 0, sizeof(strbuffer));
        if(FD_ISSET(fd, &working_set))
        {
	        bool close_conn = false;  // 标记当前连接是否断开了
			int ret = recv(fd, strbuffer,15000,0);
			//if (read(sockfd, strbuffer, 20000) == false )
	        if(!ret)
			{
				continue;
			}
			else
			{
				// Sprintf_HexData("data is ", (unsigned char*)strbuffer, sizeof(strbuffer));
            
				if(strbuffer[0] == 0x68)
				{
					if (strbuffer[1] == 0x00 && strbuffer[2] == 0x10)   //实时数据
					{
						int length = 0;
						length = (0xff & strbuffer[6]) | (0xff00 & (strbuffer[5] << 8)) | (0xff0000 & (strbuffer[4] << 16)) | (0xff000000 & (strbuffer[3] << 24));
					    this->m_data.clear();

						printf("length is %d\n", length);
						
						unsigned short rtSize =  (unsigned short)((unsigned short)strbuffer[7] << 8 | (unsigned short)strbuffer[8]);
						printf("rt size is %u\n", rtSize);
                        pthread_mutex_lock(&this->mapmutex);
						for(int ii = 0; ii < rtSize; ii++)
						{
							int value = 0;
							s_package s_pack;
                            RT_DATA* s_rtdata = new(RT_DATA);
							
	                        memset(&s_pack, 0, sizeof(s_pack));
	                        memcpy(s_pack.name, strbuffer + (9 + 68*ii), 64);

                            memcpy(s_rtdata->dev_code, strbuffer + (9 + 68*ii), 64);

                            string name = s_pack.name;

							value = (0xff & strbuffer[68*ii + 76]) | (0xff00 & (strbuffer[68*ii + 75] << 8))\
									 | (0xff0000 & (strbuffer[68*ii + 74] << 16)) | (0xff000000 & (strbuffer[68*ii + 73] << 24));

                            vector<char> tmp;
                            tmp.push_back(strbuffer[68*ii + 76]);
                            tmp.push_back(strbuffer[68*ii + 75]);
                            tmp.push_back(strbuffer[68*ii + 74]);
                            tmp.push_back(strbuffer[68*ii + 73]);
   
							s_pack.val = (float)value;
                            s_rtdata->fval = (float)value;

                            if(strlen(s_pack.name))
                            {
                                 if(this->v_data.size() > 1000 )
                                 {
                                     this->v_data.pop_front();
                                 }
                                 else
                                 {
                                     this->v_data.push_back(s_pack);
                                 }

                                this->v_RTDATA.push_back(*s_rtdata);
                                this->m_data.insert(make_pair(name, (float)value));
                            }
						}
                        pthread_mutex_unlock(&this->mapmutex);


						mmap[fd].second = 0;        // 每次收到心跳包，count置0
						char responbuf[4] = {0};
						responbuf[0] = 0x00;
						responbuf[1] = 0x10;
						responbuf[2] = 0x01;
						responbuf[3] = 0x00;
						
						// int sret = send(fd, responbuf, strlen(responbuf), 0);
		                // if (sret != strlen(responbuf))
		                //    std::cout << "send data error." << std::endl;
		                // else
		                //    std::cout << "send data to client successfully, data: " << responbuf << std::endl;
					}
					else if(strbuffer[1] == 0x01 && strbuffer[2] == 0x00)  //心跳报文
					{ 
						mmap[fd].second = 0;        // 每次收到心跳包，count置0
                        cout << "Received heart-beat from client.\n";
					}
				} 
				else
				{
					continue;
				}
			}
	 
            if(close_conn)  // 当前这个连接有问题，关闭它
            {
                close(fd);
                FD_CLR(fd, &master_set);
                if(fd == max_fd)  // 需要更新max_fd;
                {
                    while(FD_ISSET(max_fd, &master_set) == false)
                        --max_fd;
                }
            }
        }
    }   
}
 
void Server::Run()
{
    pthread_t id;     // 创建心跳检测线程
    int ret = pthread_create(&id, NULL, heart_handler, (void*)this);
    if(ret != 0)
    {
        cout << "Can not create heart-beat checking thread.\n";
    }
 
    max_fd = listen_fd;   // 初始化max_fd
    FD_ZERO(&master_set);
    FD_SET(listen_fd, &master_set);  // 添加监听fd
 
    while(1)
    {
        FD_ZERO(&working_set);
        memcpy(&working_set, &master_set, sizeof(master_set));
 
        timeout.tv_sec = 10;
        timeout.tv_usec = 0;
 
        int nums = select(max_fd+1, &working_set, NULL, NULL, &timeout);
        if(nums < 0)
        {
            cout << "select() error!";
//            exit(1);
        }
 
        if(nums == 0)
        {
            //cout << "select() is timeout!";
            continue;
        }
 
        if(FD_ISSET(listen_fd, &working_set))
            Accept();   // 有新的客户端请求
        else
            Recv(nums); // 接收客户端的消息
    }
}

